home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / program / swagn_r.zip / OOP.SWG / 0050_Alternative Sorts in TVISON.pas < prev    next >
Pascal/Delphi Source File  |  1995-03-03  |  11KB  |  341 lines

  1. {
  2.  DC> I'm setting up a directory list with some extra bells and whistles,
  3.  DC> including descriptions. I want to be able to have different sort criteria
  4.  DC> for the list, and the list should be in a
  5.  DC> TSortedCollection.
  6.  
  7.  DC> 1. The most simple-minded. instantiate four different lists, and use just
  8.  DC> one,
  9.  
  10.  DC> 2. Alternate procedures for each type of sort, calling common routines, or
  11.  DC> passing the current collection type.
  12.  
  13.  DC> 3. A variant record to save the collection in.
  14.  
  15.  DC> The Question: Would this idea work, and do you think it's the best way to
  16.  DC> do it?
  17.  
  18. I have one program with the same problem, and I can suggest two more ways to do
  19. what you want:
  20. 4.  A field in the collection saying which kind of sort you want, and a Resort
  21. method.  The KeyOf and/or Compare methods look at this field to decide how two
  22. records compare, and the Resort method re-inserts everything after you change
  23. the field, so it ends up in the correct order.
  24. 5.  A non-method SortCollection function, that takes a Compare function as a
  25. procedural parameter.  You can use a TCollection if you're not interested in
  26. the search functions, or some variation on 4 if you are.
  27.  
  28. I don't know which you'll find best.  Depends on your taste.  Here's some code
  29. that I use; you may want to borrow from it.
  30.   {$N-,Q-}
  31.   unit sorts;
  32.  
  33.   interface
  34.  
  35.   uses objects,base3;  { base3 can also be found in the SWAG collection !! }
  36.  
  37.   type
  38.     comparison = function(a,b:pointer):boolean;
  39.     { Returns true if a^ > b^ }
  40.  
  41.     local_comparison = function(a,b:pointer;frame:word):boolean;
  42.     { A far local version of a comparison }
  43.  
  44.   procedure list_sort(var start:pointer; greater:comparison);
  45.   { Procedure to do list insertion sort on the linked list pointed to by start.
  46.     Greater points to the entry for a far function with declaration
  47.       function greater^(i,j:pointer):boolean which returns true if i^ > j^
  48.       and false otherwise.
  49.     Assumes that pointers point to pointers, i.e. links should be the first
  50.     element of records in the list.
  51.     N.B.  If enough memory is available, it seems to be faster to make the list
  52.     into an array, use arr_sort, and then un_make the array when there are
  53.     more than about 100 records.
  54.     }
  55.  
  56.   procedure arr_sort(var arr;size:word;greater:comparison);
  57.   { Procedure to do a Quicksort on the array of pointers pointed to by arr.
  58.     Greater is as in list_sort.  Makes no assumptions about what pointers
  59.     point to.
  60.     Based on Quicksort as given in Steal This Code, by F.D. Boswell, Watcom
  61. 1986.  }
  62.  
  63.   procedure SortCollection(var Coll:TCollection;GreaterP:pointer);
  64.   { Sorts a collection's pointers.  Greater should be a pointer to
  65.     a local_comparison }
  66.  
  67.   function count_list(list:pointer):longint;
  68.   { Counts the number of elements in the list}
  69.  
  70.   function make_array(list:pointer;size:longint;var arr:pointer):boolean;
  71.   { Attempts to make an array of pointers from the list.  Returns true on
  72.     success, false if it failed because not enough memory is available.  Always
  73.     creates an array with size elements, but only fills those up to the
  74.     smaller of the actual size of the list or size. }
  75.  
  76.   procedure un_make_array(var list:pointer;size:integer;var arr);
  77.   { Adjusts the pointers in the list to reflect the ordering in the array.
  78.     Doesn't check that they are all valid - be sure size reflects the
  79.     true number of pointers in the array. }
  80.  
  81.   type
  82.     PSortableCollection = ^TSortableCollection;
  83.     TSortableCollection = object(TSortedCollection)
  84.       procedure Sort;
  85.       { Puts the elements of the collection in order.  This is only necessary
  86.         if something about the sort order has changed, or elements were
  87. inserted        out of order. }
  88.     end;
  89.  
  90.   implementation
  91.  
  92.   type
  93.     list_ptr = ^list_rec;
  94.     list_rec = record
  95.       next : list_ptr;
  96.     end;
  97.     ptr_array = array[1..16380] of pointer;
  98.  
  99.   procedure list_sort(var start:pointer; greater:comparison);
  100.   var
  101.     first,rest,current,next:list_ptr;
  102.   begin
  103.     rest := list_ptr(start)^.next;     { Rest points to the uninserted part of
  104. the list }    first := start;          { first is a fake first entry in the new
  105. list }    first^.next := nil;
  106.     start := @first;
  107.     while rest <> nil do
  108.     begin
  109.       current := start;
  110.       next := current^.next;
  111.       while (next <> nil) and (not greater(next,rest)) do
  112.       begin
  113.         current := next;
  114.         next := current^.next;
  115.       end;
  116.       current^.next := rest;
  117.       current := rest;
  118.       rest := rest^.next;
  119.       current^.next := next;
  120.     end;
  121.     start := first;
  122.   end;
  123.  
  124.   procedure arr_sort(var arr;size:word;greater:comparison);
  125.   { Procedure to do a Quicksort on the array of pointers pointed to by arr.
  126.     Greater is as in list_sort.  Makes no assumptions about what pointers
  127.     point to.
  128.     Based on Quicksort as given in Steal This Code, by F.D. Boswell, Watcom
  129. 1986.  }
  130.   var
  131.     a:ptr_array absolute arr;
  132.  
  133.     procedure quick(first,last : word);
  134.     var
  135.       pivot : pointer;
  136.       temp : pointer;
  137.       scanright, scanleft : word;
  138.     begin
  139.       if (first < last) then
  140.       begin
  141.         pivot := a[first];
  142.         scanright := first;
  143.         scanleft := last;
  144.         while scanright < scanleft do
  145.         begin
  146.           if greater(a[scanright+1], pivot) then
  147.           begin
  148.             if not greater(a[scanleft], pivot) then
  149.             begin
  150.               temp := a[scanleft];
  151.               inc(scanright);
  152.               a[scanleft] := a[scanright];
  153.               a[scanright] := temp;
  154.               dec(scanleft);
  155.             end
  156.             else
  157.               dec(scanleft);
  158.           end
  159.           else
  160.             inc(scanright);
  161.         end;
  162.         temp := a[scanright];
  163.         a[scanright] := a[first];
  164.         a[first] := temp;
  165.         quick(first, scanright-1);
  166.         quick(scanright+1, last);
  167.       end;
  168.     end;
  169.   begin  {arr_sort}
  170.     quick(1, size);
  171.   end;
  172.  
  173.  
  174.   function count_list(list:pointer):longint;
  175.   { Counts the number of elements in a list }
  176.   var
  177.     l:list_ptr absolute list;
  178.     size:longint;
  179.   begin
  180.     size := 0;
  181.     while l <> nil do
  182.     begin
  183.       inc(size);
  184.       l := l^.next;
  185.     end;
  186.     count_list := size;
  187.   end;
  188.  
  189.   function make_array(list:pointer;size:longint;var arr:pointer):boolean;
  190.   { Attempts to make an array of pointers from the list.  Returns true on
  191.     success, false if it failed because not enough memory is available }
  192.   var
  193.     l:list_ptr absolute list;
  194.     mem_needed:longint;
  195.     a:^ptr_array absolute arr;
  196.     i:integer;
  197.   begin
  198.     mem_needed := size*sizeof(pointer);
  199.     if (mem_needed > 65520) or (mem_needed > MemAvail) then
  200.     begin
  201.       make_array := false;
  202.       exit;
  203.     end;
  204.     GetMem(a,mem_needed);
  205.     i := 0;
  206.     while (i<size) and (l <> nil) do
  207.     begin
  208.       inc(i);
  209.       a^[i] := l;
  210.       l := l^.next;
  211.     end;
  212.     make_array := true;
  213.   end;
  214.  
  215.   procedure un_make_array(var list:pointer;size:integer;var arr);
  216.   { Adjusts the pointers in the list to reflect the ordering in the array.
  217.     Doesn't check that they are all valid - be sure size reflects the
  218.     true number of pointers in the array. }
  219.   var
  220.     l:list_ptr absolute list;
  221.     current,next:list_ptr;
  222.     a:ptr_array absolute arr;
  223.     i:integer;
  224.   begin
  225.     l := a[1];
  226.     current := l;
  227.     for i := 2 to size do
  228.     begin
  229.       next := a[i];
  230.       current^.next := next;
  231.       current := next;
  232.     end;
  233.     current^.next := nil;
  234.   end;
  235.  
  236.   procedure TSortableCollection.Sort;
  237.   { Procedure to do a Quicksort on the collection elements.
  238.     Based on Quicksort as given in Steal This Code, by F.D. Boswell, Watcom
  239. 1986.  }
  240.     procedure quick(first,last : word);
  241.     var
  242.       pivot : pointer;
  243.       temp : pointer;
  244.       scanright, scanleft, tielimit : word;
  245.       direction : integer;
  246.     begin
  247.       if (first+1) < (last+1) then  { This allows for last=-1 }
  248.       begin
  249.         { First, choose a random pivot }
  250.         scanright := first+random(last-first);
  251.         pivot := items^[scanright];
  252.         items^[scanright] := items^[first];
  253.         items^[first] := pivot;
  254.  
  255.         scanright := first;
  256.         scanleft := last;
  257.         tielimit := (first+last) div 2;
  258.         while scanright < scanleft do
  259.         begin
  260.           direction := compare(items^[scanright+1], pivot);
  261.           if (direction>0) or ((direction = 0) and (scanright > tielimit)) then
  262.           begin
  263.             if compare(items^[scanleft], pivot)<=0 then
  264.             begin
  265.               temp := items^[scanleft];
  266.               inc(scanright);
  267.               items^[scanleft] := items^[scanright];
  268.               items^[scanright] := temp;
  269.               dec(scanleft);
  270.             end
  271.             else
  272.               dec(scanleft);
  273.           end
  274.           else
  275.             inc(scanright);
  276.         end;
  277.         temp := items^[scanright];
  278.         items^[scanright] := items^[first];
  279.         items^[first] := temp;
  280.         quick(first, scanright-1);
  281.         quick(scanright+1, last);
  282.       end;
  283.     end;
  284.   begin  {sort}
  285.     quick(0, pred(count));
  286.   end;
  287.  
  288.   procedure SortCollection(var Coll:TCollection;GreaterP:pointer);
  289.   { Procedure to do a Quicksort on the collection elements.
  290.     Based on Quicksort as given in Steal This Code, by F.D. Boswell, Watcom
  291. 1986.  }
  292.   var
  293.     Greater : local_comparison absolute GreaterP;
  294.     Frame : word;
  295.  
  296.     procedure quick(first,last : word);
  297.     var
  298.       pivot : pointer;
  299.       temp : pointer;
  300.       scanright, scanleft : word;
  301.     begin
  302.       with Coll do
  303.       begin
  304.         if (first+1) < (last+1) then  { This allows for last=-1 }
  305.         begin
  306.           pivot := items^[first];
  307.           scanright := first;
  308.           scanleft := last;
  309.           while scanright < scanleft do
  310.           begin
  311.             if greater(items^[scanright+1], pivot, Frame) then
  312.             begin
  313.               if not greater(items^[scanleft], pivot, Frame) then
  314.               begin
  315.                 temp := items^[scanleft];
  316.                 inc(scanright);
  317.                 items^[scanleft] := items^[scanright];
  318.                 items^[scanright] := temp;
  319.                 dec(scanleft);
  320.               end
  321.               else
  322.                 dec(scanleft);
  323.             end
  324.             else
  325.               inc(scanright);
  326.           end;
  327.           temp := items^[scanright];
  328.           items^[scanright] := items^[first];
  329.           items^[first] := temp;
  330.           quick(first, scanright-1);
  331.           quick(scanright+1, last);
  332.         end;
  333.       end;
  334.     end;
  335.   begin  {sort}
  336.     frame := CallerFrame;
  337.     quick(0, pred(coll.count));
  338.   end;
  339.  
  340.   end.
  341.